package main

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"github.com/gin-gonic/gin"
	"net/http"
	"github.com/gomodule/redigo/redis"
	"fmt"
	"github.com/json-iterator/go"
	"github.com/Shopify/sarama"
	"gitee.com/zhucheer/orange/queue"
	"time"
)

type Student struct{
	Id string
	Name string
	Birth string
	Sex string
	CreateTime time.Time
	UpdateTime time.Time
	CourseList []*Course `gorm:"many2many:scores;"`
}

type Course struct{
	Id string
	Name string
	TeacherId string
	CreateTime time.Time
	UpdateTime time.Time
	Score Score
	Teacher Teacher `gorm:"ForeignKey:TeacherId;AssociationForeignKey:T_id"`
}

type Teacher struct{
	Id string
	Name string
	CreateTime time.Time
	UpdateTime time.Time
}

type Score struct{
	StudentId string
	CourseId  string
	Score string
	CreateTime time.Time
	UpdateTime time.Time
}

func main() {

	pool := &redis.Pool{
		MaxIdle : 10,
		MaxActive : 0,
		IdleTimeout : 100,
		Dial : func()(redis.Conn, error){
			return redis.Dial("tcp", "127.0.0.1:6379")
		},
	}
	poolConn := pool.Get()

	db, err := gorm.Open("mysql", "root:new_password@tcp(localhost:3306)/student_gorm?charset=utf8&parseTime=true")
	if err != nil {
		panic("failed to connect database")
	}
	defer db.Close()

	db.AutoMigrate(&Student{}, &Course{}, &Teacher{}, &Score{})

	config := sarama.NewConfig()
	config.Producer.RequiredAcks = sarama.WaitForAll
	config.Producer.Partitioner = sarama.NewRandomPartitioner
	config.Producer.Return.Successes = true

	client, err := sarama.NewSyncProducer([]string{"127.0.0.1:9092"}, config)
	if err != nil {
		fmt.Println("producer close, err:", err)
		return
	}
	defer client.Close()

	router := gin.Default()
	router.GET("/query", func(c *gin.Context) {
		var s []*Student
		db.Find(&s)
		for _, v := range s{
			db.Joins("JOIN scores ON scores.course_id = courses.id AND scores.student_id = ?", v.Id).Find(&v.CourseList)
			//db.Model(&v).Association("CourseList").Find(&v.CourseList)
			for _, cv := range v.CourseList{
				db.Where("course_id = ? AND student_id = ?", cv.Id, v.Id).Find(&cv.Score)
				db.Joins("JOIN courses ON courses.teacher_id = teachers.id AND courses.id = ?", cv.Id).Find(&cv.Teacher)
				//db.Model(&cv).Related(&cv.Teacher)

			}
		}

		res, jerr:= jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(&s)
		if jerr != nil{
			c.JSON(http.StatusOK, map[string]interface{}{"code":500, "message":"序列化失败"})
			return
		}
		_, dErr := poolConn.Do("Set", "student_110", string(res), "ex", 3600)
		if err != nil{
			fmt.Println(dErr)
			c.JSON(http.StatusOK, map[string]interface{}{"code":500, "message":"插入缓存失败"})
			return
		}


		msg := &sarama.ProducerMessage{}
		msg.Topic = "nginx_log"
		msg.Value = sarama.StringEncoder(string(res))
		msg.Timestamp = time.Now()

		pid, offset, err := client.SendMessage(msg)
		if err != nil {
			fmt.Println("send message failed,", err)
			return
		}

		fmt.Printf("pid:%v offset:%v\n", pid, offset)


		mqProducerClient := queue.RegisterRocketProducerMust([]string{"127.0.0.1:9876"}, "test", 1)
		ret,_:=mqProducerClient.SendMsg("topicTest", string(res))
		fmt.Println("========producer push one message====", ret.MsgId)

		c.JSON(http.StatusOK, s)
	})

	router.POST("/queryCache", func(c *gin.Context) {

		var s []*Student
		res, err := poolConn.Do("Get", "student_110")
		if res == nil ||err != nil{
			fmt.Println("err：", err)
			c.JSON(http.StatusOK, map[string]interface{}{"code":500, "message":"获取缓存失败"})
			return
		}
		fmt.Println("res：", res)

		jerr := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(res.([]byte), &s)
		if jerr != nil{
			c.JSON(http.StatusOK, map[string]interface{}{"code":500, "message":"反序列化失败"})
			fmt.Println("jerr：", jerr)
		}

		fmt.Println("s", s)

		// c.Header("content-type","application/json")
		// c.Writer.WriteString(res)

		c.JSON(http.StatusOK, s)
		return
	})

	router.POST("/queryStudentById", func(c *gin.Context) {

		id := c.PostForm("id")

		var s Student
		res, err := poolConn.Do("Get", "student_"+id)
		if res == nil || err != nil{
			fmt.Println("查数据库。。。。")
			db.Where("id = ?", id).First(&s)
			c.JSON(http.StatusOK, s)
			return
		}
		fmt.Println("res：", res)

		jerr := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(res.([]byte), &s)
		if jerr != nil{
			fmt.Println("jerr：", jerr)
		}

		fmt.Println("s", s)

		// c.Header("content-type","application/json")
		// c.Writer.WriteString(res)

		c.JSON(http.StatusOK, s)
		return
	})

	router.POST("/insert", func(c *gin.Context) {

		id := c.PostForm("id")
		name := c.PostForm("name")
		birth := c.PostForm("birth")
		sex := c.PostForm("sex")

		s := Student{
			Id: id,
			Name: name,
			Birth: birth,
			Sex: sex,
			CreateTime: time.Now(),
			UpdateTime: time.Now(),
		}
		db.Create(&s)

		res, jerr:= jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(&s)
		if jerr != nil{
			c.JSON(http.StatusOK, map[string]interface{}{"code":500, "message":"反序列化失败"})
			return
		}
		_, dErr := poolConn.Do("Set", "student_"+id, string(res), "ex", 3600)
		if err != nil{
			fmt.Println(dErr)
			c.JSON(http.StatusOK, map[string]interface{}{"code":500, "message":"插入缓存失败"})
			return
		}
		c.JSON(http.StatusOK, map[string]interface{}{"code":200, "message":"插入成功"})
		return
	})

	router.POST("/update", func(c *gin.Context) {

		id := c.PostForm("id")
		name := c.PostForm("name")
		birth := c.PostForm("birth")
		sex := c.PostForm("sex")

		s := Student{
			Id: id,
			Name: name,
			Birth: birth,
			Sex: sex,
			CreateTime: time.Now(),
			UpdateTime: time.Now(),
		}
		db.Save(&s)

		res, jerr:= jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(&s)
		if jerr != nil{
			c.JSON(http.StatusOK, map[string]interface{}{"code":500, "message":"反序列化失败"})
			return
		}
		_, dErr := poolConn.Do("Set", "student_"+id, string(res), "ex", 3600)
		if dErr != nil{
			fmt.Println(dErr)
			c.JSON(http.StatusOK, map[string]interface{}{"code":500, "message":"更新缓存失败"})
			return
		}
		c.JSON(http.StatusOK, map[string]interface{}{"code":200, "message":"更新成功"})
		return
	})

	router.POST("/delete", func(c *gin.Context) {

		id := c.PostForm("id")

		s := Student{
			Id: id,
		}
		db.Delete(&s)

		_, dErr := poolConn.Do("Del", "student_"+id, s)
		if err != nil{
			fmt.Println(dErr)
			c.JSON(http.StatusOK, map[string]interface{}{"code":500, "message":"删除缓存失败"})
			return
		}
		c.JSON(http.StatusOK, map[string]interface{}{"code":200, "message":"删除成功"})
		return
	})

	router.Run(":9200")
}

